/*
 * Copyright (c) 2020, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include "atom.h"
#include <stdio.h>
#include "atomtimer.h"
#include "atomport-private.h"
#include "board.h"
#include "event.h"
#include "debug.h"
#include "console.h"
#include <string.h>
#include "iosdrv.h"
#include "eventmgr.h"
#include "a7139.h"
#include "epaper.h"
#include "rtc.h"
#include "packet.h"

/* Constants */

/* Local data */

/* Application threads' TCBs */
static ATOM_TCB main_tcb = DEFAULT_TCB("main");

/* Main thread's stack area */
static uint8_t main_thread_stack[ATOM_MAIN_STACK_SIZE_BYTES];

/* Idle thread's stack area */
static uint8_t idle_thread_stack[ATOM_IDLE_STACK_SIZE_BYTES];

/* Forward declarations */
static void main_thread_func (uint32_t data);

/**
 * \b main
 *
 * Program entry point.
 *
 * Creates an application thread and starts the OS.
 */

static void idle_hook(void)
{
    wfi();
}

void main ( void )
{
    int8_t status;

#ifdef COM_USE_CONSOLE
    ConsoleInit();
    DebugInit();
#endif    

    IosDrvInit();
    board_init();
    DebugPortSetDevice(BSP_DBGPORT_DEVICE_NAME);
    /**
     * Note: to protect OS structures and data during initialisation,
     * interrupts must remain disabled until the first thread
     * has been restored. They are reenabled at the very end of
     * the first thread restore, at which point it is safe for a
     * reschedule to take place.
     */

    /**
     * Initialise the OS before creating our threads.
     */
    archInitSystemTickTimer();
             
    status = atomOSInit(&idle_thread_stack[0], ATOM_IDLE_STACK_SIZE_BYTES, TRUE);
    
     if (status == ATOM_OK)
     {
          atomIdleSetHook(idle_hook);
          
          /* Create an application thread */ 
          status = atomThreadCreate(&main_tcb,
                       16, main_thread_func, 0,
                       &main_thread_stack[0],
                       ATOM_MAIN_STACK_SIZE_BYTES,
                       TRUE);
 
         if (status == ATOM_OK)
          {
            /**
              * First application thread successfully created. It is
              * now possible to start the OS. Execution will not return
              * from atomOSStart(), which will restore the context of
              * our application thread and start executing it.
              *
              * Note that interrupts are still disabled at this point.
              * They will be enabled as we restore and execute our first
              * thread in archFirstThreadRestore().
              */
              atomOSStart();
          }
     }

    while (1)
        ;

    /* There was an error starting the OS if we reach here */
    //return (0);
}

static void a7139_recv_packet(PacketSyncRtc *packet)
{
    Uint8 tmpbuf[64];

    A7139_startRecv();
    KPrint("Starting rtc sync packet...\r\n");

    while(1) {
        if( !A7139_isBusy() ){
            A7139_fifoRead(tmpbuf);
            KDumpPrint(tmpbuf, 16);
            PacketHeader *header = (PacketHeader *)tmpbuf;
            if( header->id == PACKET_ID_SYNC_RTC && header->header == PACKET_HEADER){
                memcpy(packet, tmpbuf, sizeof(PacketSyncRtc));
                break;
            }else{
                A7139_startRecv();
            }
        }
        else{
            atomTimerDelay(10);
        }
    }
}


#if defined(COM_USE_DBGPORT) && defined(APP_USE_LOG)
static const char logo[] = {
"\r\n\
--------------------------------------------- \r\n\
 __   __  _______  _______  ___      _______  \r\n\
|  |_|  ||   _   ||       ||   |    |       | \r\n\
|       ||  |_|  ||    _  ||   |    |    ___| \r\n\
|       ||       ||   |_| ||   |    |   |___  \r\n\
|       ||       ||    ___||   |___ |    ___| \r\n\
| ||_|| ||   _   ||   |    |       ||   |___  \r\n\
|_|   |_||__| |__||___|    |_______||_______| \r\n\
                                              \r\n\
                    powered   by yifengling0  \r\n\
                    ver "APP_VERSION" "__DATE__"      \r\n\
                      QQ Qun: 43141468 ←      \r\n\
--------------------------------------------- \r\n\
"
};
#endif
#define RTC_WAKEUP_TICK (20)

static int is_power_save_time()
{
    int year, month, day, hour, minute, second;
    RtcGetDatetime(&year, &month, &day, &hour, &minute, &second);

    if( hour >= 23 || hour < 6 ){
        return 1;
    }else{
        return 0;
    }
}

/**
 * \b main_thread_func
 *
 * Entry point for main application thread.
 *
 * This is the first thread that will be executed when the OS is started.
 *
 * @param[in] data Unused (optional thread entry parameter)
 *
 * @return None
 */
static void main_thread_func (uint32_t data)
{
#ifdef APP_USE_LOG  
    KPrint(logo);
#endif    
    
#ifdef COM_USE_CONSOLE    
    ConsoleRun();
#endif    
    int count = 0;
    int partialCount = 0;
    PacketSyncRtc packet;

    event_mgr_init();
/* Check main thread stack usage (if enabled) */

    A7139_Init(433.921f, PKG_A7139_CID);
    A7139_GotoMode(CMD_SLEEP);

    epaper_init(RTC_WAKEUP_TICK);

    //接收a7139 数据用户同步时钟
    a7139_recv_packet(&packet);
    if( packet.header.id == PACKET_ID_SYNC_RTC){
        KPrintf("Sync RTC packet received!\r\n");
        RtcSetDatetime(*((uint16_t*)&packet.data[0]), packet.data[2], packet.data[3] ,
                       packet.data[4], packet.data[5], packet.data[6]);
    }
    //同步时间之后进度低功耗模式，要想再同步时间需要重新启动系统
    A7139_GotoMode(CMD_DEEP_SLEEP);
    epaper_showRtc(1);
    
    while(1){
        ATOM_EX_EVENT event;
        int ret = event_mgr_wait(&event, 0);
        if(ret == ATOM_OK){
            if(event.type == EVENT_RTC_WAKEUP){
                count++;
                if( count >= (60/RTC_WAKEUP_TICK)){
                    count = 0;
                    if( is_power_save_time()){
                        epaper_powerSave();
                    }else{
                        // 局刷60次一个小时候，进行一次全刷新，减少画面残影
                        partialCount++;
                        if( partialCount >= 60){
                            epaper_showRtc(1);
                            partialCount = 0;
                        }else{
                            epaper_showRtc(0);
                        }
                    }
               }
                halt();
            }
        }
    }
}